# -*- coding: utf-8 -*-
"""
心理咨询师服务系统 - 公开访问路由
"""

from flask import render_template, request, jsonify, current_app, send_file
from app.public import bp
from app.models import MemberScalePublication, Scale, ScaleQuestion, QuestionOption, Assessment, AssessmentAnswer
from app.models import ScoringRuleDimension, ScaleScoringRule, BasicInfoConfig
from app.models.assessment import AssessmentStatus
from app import db
from app.utils.helpers import success_response, error_response
from datetime import datetime
import json
import io
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.units import inch


@bp.route('/scale/<string:publication_token>')
def scale_access(publication_token):
    """通过独有链接访问量表"""
    try:
        # 查找发布记录
        publication = MemberScalePublication.query.filter_by(
            publication_token=publication_token,
            is_active=True
        ).first()
        
        if not publication:
            return render_template('public/error.html', 
                                 error_message='访问链接无效或已失效',
                                 error_code=404), 404
        
        # 获取量表信息
        scale = publication.scale
        if not scale or scale.status != 'PUBLISHED':
            return render_template('public/error.html',
                                 error_message='量表不存在或未发布',
                                 error_code=404), 404
        
        # 增加访问次数
        publication.increment_access_count()
        
        # 获取基本信息配置
        basic_info_configs = BasicInfoConfig.query.filter_by(
            status='active'
        ).order_by(BasicInfoConfig.sort_order.asc()).all()
        
        return render_template('public/scale_access.html',
                             publication=publication,
                             scale=scale,
                             basic_info_configs=basic_info_configs)
        
    except Exception as e:
        current_app.logger.error(f"访问量表失败: {str(e)}")
        return render_template('public/error.html',
                             error_message='系统错误，请稍后重试',
                             error_code=500), 500


@bp.route('/scale/<string:publication_token>/start')
def start_assessment(publication_token):
    """开始测评"""
    try:
        # 查找发布记录
        publication = MemberScalePublication.query.filter_by(
            publication_token=publication_token,
            is_active=True
        ).first()
        
        if not publication:
            return render_template('public/error.html',
                                 error_message='访问链接无效或已失效',
                                 error_code=404), 404
        
        # 获取量表和题目
        scale = publication.scale
        if not scale or scale.status != 'PUBLISHED':
            return render_template('public/error.html',
                                 error_message='量表不存在或未发布',
                                 error_code=404), 404
        
        # 获取题目和选项
        questions = ScaleQuestion.query.filter_by(
            scale_id=scale.id
        ).order_by(ScaleQuestion.question_number.asc()).all()
        
        # 为每个题目加载选项
        for question in questions:
            question.options = QuestionOption.query.filter_by(
                question_id=question.id
            ).order_by(QuestionOption.sort_order.asc()).all()
        
        return render_template('public/scale_assessment.html',
                             publication=publication,
                             scale=scale,
                             questions=questions)
        
    except Exception as e:
        current_app.logger.error(f"开始测评失败: {str(e)}")
        return render_template('public/error.html',
                             error_message='系统错误，请稍后重试',
                             error_code=500), 500


@bp.route('/scale/<string:publication_token>/assess', methods=['POST'])
def submit_assessment(publication_token):
    """提交测评"""
    try:
        # 查找发布记录
        publication = MemberScalePublication.query.filter_by(
            publication_token=publication_token,
            is_active=True
        ).first()
        
        if not publication:
            return error_response('访问链接无效或已失效', 404)
        
        scale = publication.scale
        if not scale or scale.status != 'PUBLISHED':
            return error_response('量表不存在或未发布', 404)
        
        data = request.get_json()
        if not data:
            return error_response('请求数据无效', 400)
        
        basic_info = data.get('basic_info', {})
        answers = data.get('answers', [])
        duration = data.get('duration', 0)
        
        # 创建测评记录
        assessment = Assessment(
            scale_id=scale.id,
            publication_id=publication.id,
            status=AssessmentStatus.COMPLETED,
            total_questions=len(answers),
            started_at=datetime.utcnow(),
            completed_at=datetime.utcnow()
        )
        
        db.session.add(assessment)
        db.session.flush()  # 获取assessment.id
        
        # 保存基础信息到user_basic_info表
        if basic_info:
            from app.models.user import UserBasicInfo
            from flask import session
            
            # 获取session_id（用于匿名用户）
            session_id = session.get('session_id')
            
            for field_name, field_value in basic_info.items():
                if field_value:  # 只保存有值的字段
                    user_basic_info = UserBasicInfo(
                        user_id=None,  # 匿名用户
                        session_id=session_id,
                        assessment_id=assessment.id,
                        field_name=field_name,
                        field_value=str(field_value)
                    )
                    db.session.add(user_basic_info)
        
        # 保存答案
        total_score = 0
        for answer_data in answers:
            question_id = answer_data.get('question_id')
            answer_value = answer_data.get('answer')
            
            if not question_id or not answer_value:
                continue
            
            # 获取题目
            question = ScaleQuestion.query.get(question_id)
            if not question:
                continue
            
            # 计算分数
            score = 0
            if isinstance(answer_value, list):
                # 多选题
                for value in answer_value:
                    option = QuestionOption.query.filter_by(
                        question_id=question_id,
                        option_key=value
                    ).first()
                    if option and option.option_value is not None:
                        score += option.option_value
            else:
                # 单选题或其他类型
                if question.question_type in ['single', 'scale']:
                    option = QuestionOption.query.filter_by(
                        question_id=question_id,
                        option_key=answer_value
                    ).first()
                    if option and option.option_value is not None:
                        score = option.option_value
                elif question.question_type == 'scale':
                    # 量表题直接使用数值
                    try:
                        score = float(answer_value)
                    except (ValueError, TypeError):
                        score = 0
            
            # 保存答案
            assessment_answer = AssessmentAnswer(
                assessment_id=assessment.id,
                question_id=question_id,
                answer_value=json.dumps(answer_value) if isinstance(answer_value, list) else str(answer_value),
                score=score
            )
            db.session.add(assessment_answer)
            total_score += score
        
        # 总分已计算完成，无需存储到数据库字段
        
        # 增加测评次数
        publication.increment_assessment_count()
        
        # 提交事务
        db.session.commit()
        
        return success_response('测评提交成功', {
            'assessment_id': assessment.id,
            'total_score': total_score
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"提交测评失败: {str(e)}")
        return error_response('提交失败，请稍后重试', 500)


@bp.route('/scale/<string:publication_token>/result/<int:assessment_id>')
def view_result(publication_token, assessment_id):
    """查看测评结果"""
    try:
        # 查找发布记录
        publication = MemberScalePublication.query.filter_by(
            publication_token=publication_token,
            is_active=True
        ).first()
        
        if not publication:
            return render_template('public/error.html',
                                 error_message='访问链接无效或已失效',
                                 error_code=404), 404
        
        # 查找测评记录
        assessment = Assessment.query.filter_by(
            id=assessment_id,
            publication_id=publication.id
        ).first()
        
        if not assessment:
            return render_template('public/error.html',
                                 error_message='测评记录不存在',
                                 error_code=404), 404
        
        scale = publication.scale
        
        # 计算结果
        result = calculate_assessment_result(assessment, scale)
        
        return render_template('public/scale_result.html',
                             publication=publication,
                             scale=scale,
                             assessment=assessment,
                             result=result)
        
    except Exception as e:
        current_app.logger.error(f"查看结果失败: {str(e)}")
        return render_template('public/error.html',
                             error_message='系统错误，请稍后重试',
                             error_code=500), 500


@bp.route('/assessment/<int:assessment_id>/download')
def download_result(assessment_id):
    """下载测评报告PDF"""
    try:
        # 查找测评记录
        assessment = Assessment.query.get(assessment_id)
        if not assessment:
            return error_response('测评记录不存在', 404)
        
        publication = assessment.publication
        scale = assessment.scale
        
        # 计算结果
        result = calculate_assessment_result(assessment, scale)
        
        # 生成PDF
        pdf_buffer = generate_pdf_report(assessment, scale, publication, result)
        
        # 返回PDF文件
        return send_file(
            pdf_buffer,
            as_attachment=True,
            download_name=f'{publication.custom_title or scale.title}_测评报告.pdf',
            mimetype='application/pdf'
        )
        
    except Exception as e:
        current_app.logger.error(f"下载报告失败: {str(e)}")
        return error_response('下载失败，请稍后重试', 500)


def calculate_assessment_result(assessment, scale):
    """计算测评结果"""
    try:
        # 获取评分规则
        scoring_rules = ScaleScoringRule.query.filter_by(
            scale_id=scale.id
        ).order_by(ScaleScoringRule.min_score.asc()).all()
        
        # 获取维度信息（通过评分规则）
        dimensions = []
        for rule in scoring_rules:
            dimensions.extend(rule.dimensions)
        
        # 计算总分
        answers = AssessmentAnswer.query.filter_by(
            assessment_id=assessment.id
        ).all()
        total_score = sum(answer.score for answer in answers)
        
        # 计算最大分数（从评分规则中获取）
        max_score = 100  # 默认值
        if scoring_rules:
            for rule in scoring_rules:
                if rule.max_score is not None:
                    max_score = max(max_score, rule.max_score)
        
        # 基本结果信息
        result = {
            'total_score': total_score,
            'max_score': max_score,
            'level': None,
            'level_class': 'normal',
            'description': '',
            'suggestions': [],
            'dimensions': []
        }
        
        # 根据评分规则确定等级
        for rule in scoring_rules:
            if rule.min_score is not None and rule.max_score is not None:
                if rule.min_score <= total_score <= rule.max_score:
                    result['level'] = rule.rule_name
                    result['description'] = f'您的得分为 {total_score}，在 {rule.rule_name} 范围内。'
                    result['suggestions'] = ['感谢您完成测评，建议根据结果进行进一步的专业咨询。']
                    
                    # 设置等级样式类
                    if '正常' in rule.rule_name or '良好' in rule.rule_name:
                        result['level_class'] = 'normal'
                    elif '轻度' in rule.rule_name or '轻微' in rule.rule_name:
                        result['level_class'] = 'mild'
                    elif '中度' in rule.rule_name:
                        result['level_class'] = 'moderate'
                    elif '重度' in rule.rule_name or '严重' in rule.rule_name:
                        result['level_class'] = 'severe'
                    break
        
        # 计算维度得分
        if dimensions:
            answer_dict = {answer.question_id: answer for answer in answers}
            
            for dimension in dimensions:
                dimension_score = 0
                dimension_max_score = 0
                question_count = 0
                
                # 获取该维度的题目序号
                question_numbers = [int(num.strip()) for num in dimension.question_numbers.split(',') if num.strip()]
                
                for question_number in question_numbers:
                    question = ScaleQuestion.query.filter_by(
                        scale_id=scale.id,
                        question_number=question_number
                    ).first()
                    
                    if question and question.id in answer_dict:
                        dimension_score += answer_dict[question.id].score
                        question_count += 1
                    
                    # 计算该题目的最大分数
                    if question:
                        max_option = QuestionOption.query.filter_by(
                            question_id=question.id
                        ).order_by(QuestionOption.option_value.desc()).first()
                        
                        if max_option and max_option.option_value is not None:
                            dimension_max_score += max_option.option_value
                
                result['dimensions'].append({
                    'name': dimension.dimension_name,
                    'score': dimension_score,
                    'max_score': dimension_max_score,
                    'description': ''  # ScoringRuleDimension 没有 description 字段
                })
        
        return result
        
    except Exception as e:
        current_app.logger.error(f"计算结果失败: {str(e)}")
        # 计算总分作为备用
        answers = AssessmentAnswer.query.filter_by(
            assessment_id=assessment.id
        ).all()
        total_score = sum(answer.score for answer in answers) if answers else 0
        
        return {
            'total_score': total_score,
            'max_score': 100,
            'level': '已完成',
            'level_class': 'normal',
            'description': '测评已完成，感谢您的参与。',
            'suggestions': [],
            'dimensions': []
        }


def generate_pdf_report(assessment, scale, publication, result):
    """生成PDF报告"""
    try:
        # 创建PDF缓冲区
        buffer = io.BytesIO()
        
        # 创建PDF文档
        p = canvas.Canvas(buffer, pagesize=letter)
        width, height = letter
        
        # 设置字体（如果有中文字体的话）
        try:
            # 这里需要根据实际情况设置中文字体路径
            # pdfmetrics.registerFont(TTFont('SimHei', 'path/to/simhei.ttf'))
            # p.setFont('SimHei', 16)
            p.setFont('Helvetica', 16)
        except:
            p.setFont('Helvetica', 16)
        
        # 标题
        title = publication.custom_title or scale.title
        p.drawCentredText(width/2, height - 50, f"{title} - 测评报告")
        
        # 基本信息
        y_position = height - 100
        p.setFont('Helvetica', 12)
        
        p.drawString(50, y_position, f"测评时间: {assessment.completed_at.strftime('%Y-%m-%d %H:%M')}")
        y_position -= 20
        
        p.drawString(50, y_position, f"总得分: {result['total_score']} / {result['max_score']}")
        y_position -= 20
        
        if result['level']:
            p.drawString(50, y_position, f"评估结果: {result['level']}")
            y_position -= 20
        
        # 计算用时
        if assessment.completed_at and assessment.started_at:
            duration_seconds = int((assessment.completed_at - assessment.started_at).total_seconds())
            p.drawString(50, y_position, f"用时: {duration_seconds // 60}分{duration_seconds % 60}秒")
        else:
            p.drawString(50, y_position, "用时: 未知")
        y_position -= 40
        
        # 结果描述
        if result['description']:
            p.drawString(50, y_position, "结果说明:")
            y_position -= 20
            
            # 简单的文本换行处理
            lines = result['description'].split('\n')
            for line in lines:
                if y_position < 50:
                    p.showPage()
                    y_position = height - 50
                p.drawString(70, y_position, line[:80])  # 限制每行长度
                y_position -= 15
        
        # 维度分析
        if result['dimensions']:
            y_position -= 20
            p.drawString(50, y_position, "维度分析:")
            y_position -= 20
            
            for dimension in result['dimensions']:
                if y_position < 50:
                    p.showPage()
                    y_position = height - 50
                
                p.drawString(70, y_position, f"{dimension['name']}: {dimension['score']}/{dimension['max_score']}")
                y_position -= 15
        
        # 建议
        if result['suggestions']:
            y_position -= 20
            p.drawString(50, y_position, "建议:")
            y_position -= 20
            
            for i, suggestion in enumerate(result['suggestions'][:5], 1):  # 最多显示5条建议
                if y_position < 50:
                    p.showPage()
                    y_position = height - 50
                
                p.drawString(70, y_position, f"{i}. {suggestion[:60]}...")  # 限制长度
                y_position -= 15
        
        # 免责声明
        y_position -= 30
        if y_position < 100:
            p.showPage()
            y_position = height - 50
        
        p.setFont('Helvetica', 10)
        disclaimer = "本测评结果仅供参考，不能替代专业的心理咨询或医学诊断。"
        p.drawString(50, y_position, disclaimer)
        
        # 完成PDF
        p.save()
        buffer.seek(0)
        
        return buffer
        
    except Exception as e:
        current_app.logger.error(f"生成PDF失败: {str(e)}")
        # 返回一个简单的错误PDF
        buffer = io.BytesIO()
        p = canvas.Canvas(buffer, pagesize=letter)
        p.setFont('Helvetica', 16)
        p.drawCentredText(300, 400, "PDF生成失败")
        p.save()
        buffer.seek(0)
        return buffer


@bp.route('/error')
def error_page():
    """错误页面"""
    error_message = request.args.get('message', '未知错误')
    error_code = request.args.get('code', 500)
    return render_template('public/error.html',
                         error_message=error_message,
                         error_code=error_code)